#!/usr/bin/env ruby

require 'Xml'
require 'Activity'
require 'DataObject'


class Bpmn < Xml
  ACTIVITY = { :scriptTask => "scriptTask", :serviceTask => "serviceTask", :subProcess => "subProcess", :throwEvent => "throwEvent", :startEvent => "startEvent", :signal => "signal", :sendTask => "sendTask", :receiveTask => "receiveTask", :manualTask => "manualTask", :intermediateThrowEvent => "intermediateThrowEvent", :intermediateCatchEvent => "intermediateCatchEvent", :inclusiveGateway => "inclusiveGateway", :implicitThrowEvent => "implicitThrowEvent", :eventBasedGateway => "eventBasedGateway", :endEvent => "endEvent", :complexGateway => "complexGateway", :callActivity => "callActivity", :businessRuleTask => "businessRuleTask", :boundaryEvent => "boundaryEvent", :userTask => "userTask" }
  
  def activity_collect(node)
	act = Activity.new
	label = documentation_label(node)
	act.name = (label.nil?) ? (node["name"].nil?) ? node.name : node["name"] : label
	act.type = node.name
	begin
	act.description = documentation_description(node)
	rescue
	end
	begin
	  if act.type == ACTIVITY[:startEvent] or act.type == ACTIVITY[:endEvent]
	    conv_node = node_by_id(node.xpath("#{node.path}//@conversation")[0].value)
	    act.reference = conv_node.elements[0].attribute_nodes[0].value if conv_node["type"].include? "call"
	  elsif act.type == ACTIVITY[:serviceTask] or act.type == ACTIVITY[:sendTask] or act.type == ACTIVITY[:receiveTask] or act.type == ACTIVITY[:callActivity] or act.type == ACTIVITY[:intermediateThrowEvent]
	    conv_node = node_by_id(node.xpath("#{node.path}//@conversation")[0].value)
	    act.reference = conv_node.elements[0].attribute_nodes[0].value if conv_node["type"].include? "call"
	  elsif act.type == ACTIVITY[:businessRuleTask]
	    act.reference = node.xpath("#{node.path}//@businessRuleName")[0].value
	  end
	rescue
	end
	begin
	  if act.type == ACTIVITY[:businessRuleTask]
	    act.operation = node.xpath("#{node.path}//@functionName")[0].value
	  elsif act.type == ACTIVITY[:serviceTask] or act.type == ACTIVITY[:sendTask] or act.type == ACTIVITY[:receiveTask] or act.type == ACTIVITY[:callActivity] or act.type == ACTIVITY[:intermediateThrowEvent]
	    act.operation = node.xpath("#{node.path}//*[local-name()='Conversational']//@operation")[0].value
	  elsif act.type == ACTIVITY[:startEvent] or act.type == ACTIVITY[:endEvent] or act.type == ACTIVITY[:intermediateCatchEvent]
	    act.operation = node.xpath("#{node.path}//*[local-name()='Conversational']//@definedOperationName")[0].value
	  else
	    act.operation = node['operationRef']
	  end
	rescue
	end
	begin
	  act.input = variables_input(node)
	rescue
	end
	begin
	  act.output = variables_output(node)
	rescue
	end
	act
  end

  def node_by_id(id)
    @doc.xpath("//*[@id = '#{id}']")[0]
  end

  def documentation_doc
    return @documentation_doc if !@documentation_doc.nil?
    return Xml.new(path.split("/")[0...-2].join("/")+"/"+path.split("/")[-1][0...-5]+"Documentation.xml")
  end

  def activities
    activities_doc.collect do |el|
      activity_collect el
    end
  end

  def documentation_label(node)
    documentation_doc.doc.xpath("//xmlns:topicDocumentation[@name='#{node["id"]}']//xmlns:label")[0].text
  end

  def documentation_description(node)
    documentation_doc.doc.xpath("//xmlns:topicDocumentation[@name='#{node["id"]}']//xmlns:description")[0].text
  end

  def documentation
    documentation_description @doc.elements[0].elements[0]
  end

  def activities_doc
    doc.xpath('//*').collect do |el|
      if ACTIVITY.has_value? el.name
	el
      end
    end.compact
  end

  def variables_doc
    @doc.xpath("//xmlns:dataObject")
  end

  def variables_project
    Xml.new(path.split("/")[0...-2].join("/")+"/default.bpmn").doc.xpath("//xmlns:dataObject")
  end

  def variable_to_data(node)
      var = DataObject.new
      var.name = node["name"]
      type = node.xpath("#{node.path}//@*[contains('type element',local-name())]")[0]
      var.type = type.text
      var.namespace = node.xpath("#{node.path}//@*['namespace' = local-name()]")[0].value
      var.resource_type = type.name
      var.description
      var
  end

  def variables
    @variables = variables_collect if @variables.nil?
    @variables
  end

  def variables_collect
    var = variables_doc.collect do |el|
      variable_to_data(el)
    end.compact
    var.concat(variables_project.collect do |el|
      variable_to_data(el)
    end.compact)
    var.uniq.compact
  end

  def variables_input(node)
    var=[]
    node.xpath("#{node.path}/*/xmlns:assignment//xmlns:from").each do |f|
      variables_names_from_text(f.text).each do |name|
	var << variable_by_name(name[0])
      end
    end
    var.uniq.compact
  end

  def variables_output(node)
    var=[]
    node.xpath("#{node.path}/*/xmlns:assignment//xmlns:to").each do |f|
      variables_names_from_text(f.text).each do |name|
	var << variable_by_name(name[0])
      end
    end
    var.uniq.compact
  end

  def variable_by_name(name)
    variables.select{|v| v.name == name}[0]
  end

  def variables_names_from_text(text)
    text.scan(/bpmn:getData[OutputObject]+\('(\w+)'\)/)
  end

  def type
    BPMN
  end

end

